﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Timers;

namespace Reborn_Server.App1AppHandler
{
    public class QuestCreature : Creature
    {
        public string QuestStartDialog = "";
        public string QuestFinishDialog = "";

        public List<Loot> RewardItems = new List<Loot>();
        public List<Loot> CollectionItems = new List<Loot>();

        public string QuestType = "";

        public int EscortDestinationN = -1;
        public int EscortDestinationE = -1;
        public int EscortDestinationS = -1;
        public int EscortDestinationW = -1;

        public int EscortMapID = -1;

        public bool canSeeMe = false;

        public bool RewardsAll = false;

        public string QuestStatus = "New";

        //If canSeeMe == false (Quest creature is non interactive) do not let HP go down
        public override int HP
        {
            set
            {
                if (canSeeMe == false && value < HP)
                    return;

                base.HP = value;
            }
        }
        public override bool grantExpTo(Character character)
        {
            if (canSeeMe == false)
                return false;
            else
                return true;
        }


        public override void ResetCreature()
        {
            base.ResetCreature();

            if (QuestType == "Escort")
                QuestStatus = "New";

            canSeeMe = false;
        }

        public override void SetPosition(MapItem mapItem)
        {
            base.SetPosition(mapItem);
            
            if (MapID == EscortMapID && MapX >= EscortDestinationW && MapX <= EscortDestinationE && MapY >= EscortDestinationN && MapY <= EscortDestinationS)
            {
                QuestStatus = "Complete";

                if (petController != null && petController.MasterCreature is Character)
                {
                    Character character = (Character)petController.MasterCreature;
                    GameHandler.QuestCreatureOpenWindow(character, CreatureID);
                }
            }

            if (petController != null)
            {
                Timer_EscortChangePosition.Stop();
                Timer_EscortChangePosition.Interval = 1000 * 60 * 3;
                Timer_EscortChangePosition.Start();
            }
        }

        //Timer is reset whenever the creature changes position, if the timer 
        //expires and the master is not around the escort quest ends and the creature de-spawns
        public Timer Timer_EscortChangePosition = new Timer(1000 * 60 * 3);

        public QuestCreature(AppHandler2 gameHander) : base(gameHander) 
        {
            Timer_EscortChangePosition.AutoReset = false;
            Timer_EscortChangePosition.Elapsed += new ElapsedEventHandler(Timer_EscortChangePosition_Elapsed);
        }

        //Stop the regen timer if quest creature is killed
        public override void DropLoot(int SlayingCharID)
        {
            base.DropLoot(SlayingCharID);

            Timer_Regen.Stop();
            petController = null;
        }

        protected void Timer_EscortChangePosition_Elapsed(object sender, ElapsedEventArgs e)
        {
            LockItem lockItem = GameHandler.GetLockItem(MapID, Instance);
            lock (lockItem.LockObj)
            {
                //CHECK IF WE'RE IN A VALID STATE TO CONTINUE EXECUTION/////////////////////////

                //System.Reflection.MethodBase currentMethodBase = System.Reflection.MethodBase.GetCurrentMethod();
                //Delegate currentMethodDelegate = Delegate.CreateDelegate(currentMethodBase.GetType(), this, currentMethodBase.Name);

                //Create a delegate for this method incase it cant be run right now
                Action<object, ElapsedEventArgs> thisMethod = (Action<object, ElapsedEventArgs>)Timer_EscortChangePosition_Elapsed;
                //Record this method's arguments
                Object[] thisMethodArgs = { sender, e };
                //Pass the delegate and args when we check if we're mid map transfer. If yes, they will be recorded and run again automatically.
                if (isChangingMaps(thisMethod, thisMethodArgs) == true)
                    return;

                //A map transfer happened, but its already complete. Immediately re-run this method on a different thread. 
                //We need to use a different thread because otherwise the current thread would lock 2 maps possibly resulting in a deadlock.
                if (MapID != lockItem.MapID)
                {
                    thisMethod.BeginInvoke(sender, e, null, null);
                    return;
                }
                //STATE IS VALID, CONTINUE EXECUTION///////////////////////////////////////////

                bool masterNearby = false;
                if (petController != null)
                {
                    Map CurrentMap = GameHandler.GetMap(MapID, Instance);
                    foreach (MapItem mapitem in CurrentMap.MapItems)
                    {
                        if (Math.Abs(mapitem.MapX - MapX) <= 6 && Math.Abs(mapitem.MapY - MapY) <= 6)
                        {
                            foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                            {
                                if (creaturebase == petController.MasterCreature)
                                {
                                    masterNearby = true;
                                    break;
                                }
                            }
                        }
                        if (masterNearby == true)
                            break;
                    }
                }
                if (masterNearby == true)
                {
                    Timer_EscortChangePosition.Interval = 1000 * 60 * 3;
                    Timer_EscortChangePosition.Start();
                    return;
                }

                petController = null;

                //creature has been motionless for 3 minutes and master is not nearby, despawn the quest creature
                //If HP < 1 it means the creature has been killed by something else, and whatever killed it will do the clean up
                if (HP > 0)
                {
                    //Call the base because the override will prevent us from reducing its HP if the creature is non Interactive (canSeeMe == false)
                    //This will remove all buffs, and cause the creature AI to start Respawn Timer
                    base.HP = 0;

                    Map CurrentMap = GameHandler.GetMap(MapID, Instance);
                    List<Character> CharsToUpdate = new List<Character>();
                    MapItem mapitemToUpdate = currentMapItem;
                    
                    Timer_Regen.Stop();

                    //Despawn the quest creature (do not drop loot)
                    foreach (MapItem mapitem in CurrentMap.MapItems)
                    {
                        if (mapitem.MapX == MapX && mapitem.MapY == MapY)
                        {
                            mapitem.CreaturesBases.Remove(this);
                            mapitemToUpdate = mapitem;
                        }
                        if (Math.Abs(mapitem.MapX - MapX) <= 4 && Math.Abs(mapitem.MapY - MapY) <= 4)
                        {
                            foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                            {
                                if (creaturebase is Character)
                                {
                                    CharsToUpdate.Add((Character)creaturebase);
                                }
                            }
                        }
                    }
                    foreach (Character character in CharsToUpdate)
                    {
                        character.AddMapItem(mapitemToUpdate);
                    }
                }

            }//End Lock

        }

        public void AcceptEscort(Character character)
        {
            LockItem lockitem = GameHandler.GetLockItem(MapID, Instance);
            lock (lockitem.LockObj)
            {
                //Activate the creatures AI, and flag them as viewable by mobs
                if (petController == null)
                {
                    CreatureBase thisCreature = (CreatureBase)this;
                    CreatureBase masterCreature = (CreatureBase)character;

                    petController = new Pet_Controller(thisCreature, masterCreature, null);
                    base.creatureAI.Timer_CreatureRound.Start();
                    canSeeMe = true;
                    QuestStatus = "Active";

                    Timer_Regen.Start();

                    Timer_EscortChangePosition.Stop();
                    Timer_EscortChangePosition.Interval = 1000 * 60 * 3;
                    Timer_EscortChangePosition.Start();
                }
            }

        }

        //Scans inventory for collection items, returns list of items or null if incomplete
        public List<Loot> hasCollectionItems(Character character)
        {
            List<Loot> result = new List<Loot>();

            foreach (Loot requiredItem in CollectionItems)
            {
                Loot leftHandItem = character.LeftHand;
                if (leftHandItem != null && leftHandItem.ID == requiredItem.ID && (leftHandItem.BoundTo == -1 || leftHandItem.BoundTo == character.ID) && result.Contains(leftHandItem) == false)
                {
                    result.Add(leftHandItem);
                    continue;
                }

                Loot rightHandItem = character.RightHand;
                if (rightHandItem != null && rightHandItem.ID == requiredItem.ID && (rightHandItem.BoundTo == -1 || rightHandItem.BoundTo == character.ID) && result.Contains(rightHandItem) == false)
                {
                    result.Add(rightHandItem);
                    continue;
                }

                Loot[] beltItems = character.beltManager.getBeltLootCopy();
                bool foundInBelt = false;
                for (int x = 0; x < beltItems.Length; x++)
                {
                    Loot beltLoot = beltItems[x];
                    if (beltLoot != null && beltLoot.ID == requiredItem.ID && (beltLoot.BoundTo == -1 || beltLoot.BoundTo == character.ID) && result.Contains(beltLoot) == false)
                    {
                        result.Add(beltLoot);
                        foundInBelt = true;
                        break;
                    }
                }
                if (foundInBelt == true)
                    continue;

                List<Loot> bagItems = character.bagManager.getAllBagItems();
                bool foundInBag = false;
                for (int x = 0; x < bagItems.Count; x++)
                {
                    Loot bagLoot = bagItems[x];
                    if (bagLoot != null && bagLoot.ID == requiredItem.ID && (bagLoot.BoundTo == -1 || bagLoot.BoundTo == character.ID) && result.Contains(bagLoot) == false)
                    {
                        result.Add(bagLoot);
                        foundInBag = true;
                        break;
                    }
                }
                if (foundInBag == true)
                    continue;

                return null;
            }

            return result;
        }
    }
}
